<template>
  <div class="logic-flow-view">
    <Control
      class="demo-control"
      v-if="lf"
      :lf="lf"
      :graphData="graphData"
      @exportData="$_exportData"
      @data-import="$_importData"
      @clear="$_clear"
    />
    <NodePanel v-if="lf" :lf="lf" :nodeList="nodeList" />
    <div ref="container" class="LF-view"></div>
    <EditDialog
      :dialog-visible.sync="dialogVisible"
      :form-data="formData"
      @data-update="$_dataUpdate" />
  </div>
</template>

<script>
import LogicFlow from '@logicflow/core'
import '@logicflow/core/dist/style/index.css'
import { Menu, Group, DndPanel, Snapshot, SelectionSelect } from '@logicflow/extension'
import '@logicflow/extension/lib/style/index.css'
import { nodeList } from './config/init.js'
import NodePanel from './MSFGComponents/NodePanel'
import Control from './MSFGComponents/Control'
import EditDialog from './EditDialog.vue'
import './registerNode/tools/style.css'
import {
  BaseNode,
  SwitchNode,
  TestNode,
  FaultNode,
  SubSystem,
  CustomEdge
} from './registerNode/index.js'

export default {
  name: 'MSFG',
  components: {
    NodePanel: NodePanel,
    Control: Control,
    EditDialog: EditDialog
  },
  data () {
    return {
      lf: null,
      showAddPanel: false,
      addPanelStyle: {
        top: 0,
        left: 0
      },
      nodeData: null,
      addClickNode: null,
      clickNode: null,
      dialogVisible: false,
      graphData: null,
      dataVisible: false,
      moveData: {},
      nodeList,
      formData: {},
    }
  },
  mounted () {
    this.$_initLf()
    this.lf.extension.selectionSelect.setSelectionSense(true, true)
  },
  methods:{
    // 初始化logicFlow
    $_initLf () {
      // 画布配置
      const lf = new LogicFlow({
        container: this.$refs.container,
        nodeTextEdit: false, // 禁用节点文本编辑
        edgeTextEdit: false, // 禁用边文本编辑
        adjustEdgeMiddle: true, // 只对折线生效，只允许调整边的中间线段，不允许调整与起点终点相连的线段
        keyboard: {
          enabled: true
        },
        grid: {
          visible: true,
          type: 'mesh',
          size: 10,
          config: {
            color: '#eeeeee'
          }
        },
        plugins: [
          Menu,
          Group,
          Snapshot,
          DndPanel,
          SelectionSelect
        ],
      })
      this.lf = lf
      this.$_registerNode()
    },
    // 注册节点
    $_registerNode () {
      this.lf.register(BaseNode)
      this.lf.register(TestNode)
      this.lf.register(FaultNode)
      this.lf.register(SwitchNode)
      this.lf.register(SubSystem)
      this.lf.register(CustomEdge)
      this.lf.setDefaultEdgeType('custom-edge')
      // this.lf.setDefaultEdgeType("bezier")
      this.$_render()
    },
    // 渲染数据
    $_render () {
      // 为菜单栏定义新的操作
      this.lf.extension.menu.setMenuByType({
        type: 'lf:defaultSelectionMenu',
        menu: [
          {
            text:'删除',
            callback: (select) => {
              select.nodes.map((item) => {this.lf.deleteNode(item.id)})
              select.edges.map((item) => {this.lf.deleteEdge(item.id)})
            }
          },
          {
            text:'分组',
            callback: this.$_createSub
          }
        ]
      })
      this.lf.extension.menu.setMenuConfig({
        nodeMenu: [
          {
            text: '删除',
            callback: (node) => {
              this.lf.deleteNode(node.id)
            }
          },
          {
            text: '编辑节点属性',
            callback: (node) => {
              this.lf.graphModel.eventCenter.emit('node:edit', node)
            }
          }
        ],
        edgeMenu: [
          {
            text: '删除',
            callback: (edge) => {
              this.lf.deleteEdge(edge.id)
            }
          }
        ]
      })
      this.lf.extension.menu.setMenuByType({
        type: 'sub-system',
        menu: [
          {
            text:'删除子系统',
            callback: (node) => {
              this.lf.deleteNode(node.id)
            }
          },
          {
            text:'解除子系统',
            callback: (node) => {
              let sub = this.lf.getNodeModelById(node.id)
              node.children.forEach((child) => {
                sub.removeChild(child)
              })
              this.lf.deleteNode(node.id)
            }
          }
        ]
      })
      // 为侧边栏定义新的操作
      this.lf.extension.dndPanel.setPatternItems([
        {
          label: '选区',
          icon: '',
          callback: () => {
            this.lf.extension.selectionSelect.openSelectionSelect()
            this.lf.once('selection:selected', () => {
              this.lf.extension.selectionSelect.closeSelectionSelect()
            })
          }
        },
        { // 缺有效的判断条件，用户乱用会出事，，，
          type: 'sub-system',
          label: '分组',
          icon: '',
          callback: this.$_createSub
        }
      ])
      this.lf.render({})
      this.$_LfEvent()
    },
    // 监听事件
    $_LfEvent () {
      // 单击节点 for test
      this.lf.on('node:click', ({ data }) => {
        this.currentNode = data
        console.log(data) // for test
      })
      // 双击节点
      this.lf.on('node:dbclick', ({ data }) => {
        this.formData = data
        this.dialogVisible = true
      })
      this.lf.on('node:edit', (data) => {
        this.formData = data
        this.dialogVisible = true
      })
      this.lf.on('blank:click', ({ data }) => {
        this.currentNode = null
      })
      this.lf.on('selection:selected', (data) => {

      })
      this.lf.on('group:fold', (data) => {
        if (data.isFolded === true) {
          data.foldGroup(false)
          this.foldAllChild(data.children)
          data.foldGroup(true)
        } else {
          this.unfoldAllChild(data.children)
        }
      })
      this.lf.on('anchor:drop', (data) => {
        let model = data.edgeModel
        let edges = this.lf.getEdgeModels({
          sourceNodeId: model.sourceNodeId,
          targetNodeId: model.targetNodeId
        })
        if (edges.length > 1) {
          this.$alert('重复连线')
          this.lf.deleteEdge(model.id)
        } else {
          // 开关的控制节点接入
          if (model.targetNodeId + '_top' === model.targetAnchorId || model.targetNodeId + '_bottom' === model.targetAnchorId) {
            let node = this.lf.graphModel.getNodeModelById(model.targetNodeId)
            if (node.properties.control === null) {
              node.properties.control = model.sourceNodeId
            } else {
              this.$alert('该开关已有控制节点')
              this.lf.deleteEdge(model.id)
            }
          }
        }
      })
      // 删除连线
      this.lf.on('edge:delete', ({data}) => {
        let node = this.lf.graphModel.getNodeModelById(data.targetNodeId)
        if (node.type === 'switch-node' && node.properties.control === data.sourceNodeId) {
          node.properties.control = null
        }
      })
    },
    $_createSub () {
      const { nodes } = this.lf.getSelectElements()
      // const allelement = [...nodes, ...edges]
      this.lf.clearSelectElements()

      const { startPoint, endPoint } = this.lf.extension.selectionSelect
      // if (nodes.some((node) => node.type === "ivrGroupNode")) {
      //   return
      // }
      // startPoint 和 endPoint 是 dom 坐标，需要转换成 canvas 坐标绘制
      const { transformModel } = this.lf.graphModel
      const [x1, y1] = transformModel.HtmlPointToCanvasPoint([
        startPoint.x,
        startPoint.y
      ])
      const [x2, y2] = transformModel.HtmlPointToCanvasPoint([
        endPoint.x,
        endPoint.y
      ])
      const width = x2 - x1
      const height = y2 - y1
      if (width < 175 && height < 40) {
        // 分组节点太小容易丢失，而且没必要这么小，没法缩小。。。
        return
      }
      this.lf.addNode({
        type: "sub-system",
        text: '子系统',
        x: x1 + width / 2,
        y: y1 + height / 2,
        properties: {
          nodeSize: {
            width: width,
            height: height
          }
        },
        children: nodes.map((item) => item.id)
      })
      this.lf.render(this.$data.lf.getGraphRawData())
    },
    $_dataUpdate (_node) {
      let node = this.lf.graphModel.getNodeModelById(_node.id)
      node.updateText(_node.text.value)
      node.setProperties({..._node.properties})
    },
    $_exportData () {
      this.$data.graphData = this.$data.lf.getGraphData()
    },
    $_importData (info) {
      this.lf.render(info)
    },
    $_clear () {
      this.lf.clearData()
    },
    foldAllChild (child) {
      child.forEach((nodeID) => {
        let node = this.lf.graphModel.getNodeModelById(nodeID)
        if (node.type === 'sub-system') {
          if (node.isFolded === false) {
            this.foldAllChild(node.children)
            node.foldGroup(true)
          }
          if (node.isFolded === true) {
            node.foldGroup(false)
            this.foldAllChild(node.children)
            node.foldGroup(true)
          }
        }
      })
    },
    unfoldAllChild (child) {
      child.forEach((nodeID) => {
        let node = this.lf.graphModel.getNodeModelById(nodeID)
        if (node.type === 'sub-system') {
          node.foldGroup(false)
          this.unfoldAllChild(node.children)
        }
      })
    }
  }
};
</script>

<style scoped>
.logic-flow-view {
  height: 95%;
  position: relative;
}
.demo-control {
  position: absolute;
  top: 0px;
  right: 50px;
  z-index: 2;
}
.LF-view {
  position: absolute;
  top: 0px;
  left: 150px;
  width: calc(100% - 200px);
  height: 100%;
  outline: none;
}
.node-panel {
  position: absolute;
  top: 0px;
}
</style>